//////////////////////////////////////////////
// WebUnitTests.js
//
// Logic handling for the project, renderer
// process.
//////////////////////////////////////////////

/// Constants --------------------------------

// nkEngine setup
var nkPromise = nkEngine() ;
var nk = null ;
var nkDebug = null ;
var nkExport = null ;
var nkGraphics = null ;
var nkImages = null ;
var nkLog = null ;
var nkMaths = null ;
var nkMemory = null ;
var nkWinUi = null ;

// Prepare namespaces
var nkDebugTests = {} ;
var nkGraphicsTests = {} ;
var nkImagesTests = {} ;
var nkLogTests = {} ;
var nkMathsTests = {} ;
var nkMemoryTests = {} ;
var nkScriptsTests = {} ;
var nkWinUiTests = {} ;

var nkWebUnitTests = {} ;

/// Main -------------------------------------

const launchTests = async () =>
{
	const logDiv = document.getElementById("Log") ;

	class CustomLogger extends nkLog.Logger
	{
		log (message, className)
		{
			
		}
	} ;

	class CustomOutputFormatter extends nkDebug.OutputFormatter
	{
		constructor ()
		{
			super() ;
			this._classTestSuccess = 0 ;
			this._classTestFailure = 0 ;

			this._totalTestSuccess = 0 ;
			this._totalTestFailure = 0 ;

			this._totalTimeMicroS = 0 ;
		}

		formatRunLaunch (params)
		{
			return "<p class=\"TestRunInfo\">Starting test run...</p>" ;
		}

		formatRunEnd ()
		{
			return "<p class=\"TestRunInfo\">Test run complete : " + this._totalTestSuccess + "&#x2713; " + this._totalTestFailure + "&#9747; in " + (this._totalTimeMicroS / 1000) + "ms</p>" ;
		}

		formatClassLaunch (info)
		{
			// Reset
			this._classTestSuccess = 0 ;
			this._classTestFailure = 0 ;

			// Format
			return "<div class=\"TestClassInfo\">" + info.getName() + " with " + info.getClassFilteredFunctionCount() + "/" + info.getClassTotalFunctionCount() + " functions.</div>" ;
		}

		formatClassEnd (info)
		{
			return "<div class=\"TestClassInfo\">" + info.getName() + " done : " + this._classTestSuccess + "&#x2713; " + this._classTestFailure + "&#9747;</div><br/>" ;
		}

		formatTestLaunch (info)
		{

		}

		formatTestSuccess (info)
		{
			this._classTestSuccess++ ;
			this._totalTestSuccess++ ;
			this._totalTimeMicroS += info.getTimeMicroS() ;

			return "<div class=\"TestInfo_success\">&#x2713; " + info.getName() + " - " + (info.getTimeMicroS() / 1000) + "ms</div>" ;
		}

		formatTestFailure (info)
		{
			this._classTestFailure++ ;
			this._totalTestFailure++ ;
			this._totalTimeMicroS += info.getTimeMicroS() ;

			return "<div class=\"TestInfo_failure\">&#9747; " + info.getName() + " - " + (info.getTimeMicroS() / 1000) + "ms -> " + info.getRunResult().getRejectionReason() + "</div>" ;
		}
	} ;

	class CustomTestObserver extends nkDebug.TestObserver
	{
		// Constructor, destructor
		constructor ()
		{
			super() ;
			this._nunitFormatter = new nkDebug.NunitOutputFormatter () ;
			this._uiFormatter = new CustomOutputFormatter () ;
		}

		delete ()
		{
			this._nunitFormatter.delete() ;
			this._uiFormatter.delete() ;
			super.delete() ;
		}

		// Utils
		log (text)
		{
			logDiv.innerHTML += text ;
			
			requestAnimationFrame(() => 
			{
				const scrollingElement = (document.scrollingElement || document.body) ;
				scrollingElement.scrollTop = scrollingElement.scrollHeight ;
			}) ;
		}

		// Hooks
		onRunLaunch (params)
		{
			this._nunitFormatter.formatRunLaunch(params).delete() ;
			this.log(this._uiFormatter.formatRunLaunch(params)) ;
		}

		onRunEnd ()
		{
			const nunitLogs = this._nunitFormatter.formatRunEnd() ;
			window.nkWeb.writeFile("gen_results.xml", nunitLogs.getData()) ;
			this.log(this._uiFormatter.formatRunEnd()) ;

			nunitLogs.delete() ;
		}

		onClassLaunch (info)
		{
			this._nunitFormatter.formatClassLaunch(info).delete() ;
			this.log(this._uiFormatter.formatClassLaunch(info)) ;
		}

		onClassBypass (info)
		{
			this._nunitFormatter.formatClassBypass(info).delete() ;
		}

		onClassEnd (info)
		{
			this._nunitFormatter.formatClassEnd(info).delete() ;
			this.log(this._uiFormatter.formatClassEnd(info)) ;
		}

		onTestLaunch (info)
		{
			this._nunitFormatter.formatTestLaunch(info).delete() ;
		}

		onTestBypass (info)
		{
			this._nunitFormatter.formatTestBypass(info).delete() ;
		}

		onTestSuccess (info)
		{
			this._nunitFormatter.formatTestSuccess(info).delete() ;
			this.log(this._uiFormatter.formatTestSuccess(info)) ;
		}

		onTestFailure (info)
		{
			this._nunitFormatter.formatTestFailure(info).delete() ;
			this.log(this._uiFormatter.formatTestFailure(info)) ;
		}
	} ;

	var logger = new CustomLogger () ;
	nk.nkDebug.LogManager.getInstance().setReceiver(logger) ;

	var observer = new CustomTestObserver () ;
	var runParameters = new nk.nkDebug.TestRunParameters () ;
	runParameters.setObserver(observer) ;

	await nk.nkDebug.UnitTester.run(runParameters) ;

	nk.nkDebug.LogManager.getInstance().setReceiver(null) ;
	logger.delete() ;
	observer.delete() ;

	const isCi = await window.nkWeb.isCi() ;

	if (isCi)
		window.nkWeb.closeApp() ;
}

const forwardException = (e) =>
{
	console.error(e.stack) ;
	window.nkWeb.writeFile("gen_error.log", e.stack) ;
	window.nkWeb.forwardException(e.stack) ;
}

const main = async () =>
{
	// List tests
	const files = await window.nkWeb.listTestFiles() ;
	var counter = 0 ;

	for (const file of files)
	{
		const s = document.createElement("script") ;
		s.onload = async function () {try {counter++ ; if (counter >= files.length) await launchTests() ;} catch (e) {forwardException(e) ;}} ;
		s.src = file ;

		document.head.appendChild(s) ;
	}
} ;

/// Loading ----------------------------------

nkPromise.then
(
	async function (nkEngine)
	{
		nk = nkEngine ;
		nkDebug = nk.nkDebug ;
		nkExport = nk.nkExport ;
		nkGraphics = nk.nkGraphics ;
		nkImages = nk.nkImages ;
		nkLog = nk.nkLog ;
		nkMaths = nk.nkMaths ;
		nkMemory = nk.nkMemory ;
		nkScripts = nk.nkScripts ;
		nkWinUi = nk.nkWinUi ;

		await main() ;
	}
) ;
